/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package model.util;

import java.sql.*;
import java.sql.Date;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.config.ConnectionConfig;

/**
 *
 * @author QuocThanh
 */
public class MySQLProviders {

   /**
    * Thuộc tính đối tượng kết nối cơ sở dữ liệu
    */
   private Connection connection;

   /**
    * Phương thức cung cấp đối tượng kết nối đến cơ sở dữ liệu
    * @return đối tượng kết nối
    */
   public Connection getConnection() {
      return connection;
   }

   /**
    * Mở kết nối đến cơ sở dữ liệu
    */
   public void open() {
      try {
         DriverManager.registerDriver(new org.gjt.mm.mysql.Driver());
         ConnectionConfig connectionConfig=new ConnectionConfig();
         if(connectionConfig.Read()){
             String connectionString =String.format("%s:%s://%s:%d/%s?useUnicode=true&characterEncoding=UTF-8",
                     connectionConfig.getTypeConnection(),connectionConfig.getTypeData(),connectionConfig.getHost(),connectionConfig.getPort(),connectionConfig.getDatabase());
             Properties pros = new Properties();
             pros.setProperty("characterEncoding",connectionConfig.getEncoding());
             pros.setProperty("user", connectionConfig.getUser());
             pros.setProperty("password", connectionConfig.getPassword());
             this.connection = DriverManager.getConnection(connectionString, pros);
         }
         
      } catch (SQLException ex) {
         System.out.println(ex.getMessage());
      }
   }

   /**
    * Đóng kết nối cơ sở dữ liệu
    */
   public void close() {
      try {
         this.connection.close();
      } catch (SQLException ex) {
         Logger.getLogger(MySQLProviders.class.getName()).log(Level.SEVERE, null, ex);
      }
   }

   /**
     * Phương thức thực thi chuỗi truy vấn
     * @param strQuery:chuỗi truy vấn
     * @return :ResultSet
     */
    public ResultSet executeQuery(String strQuery) {
       ResultSet rs = null;
       Statement sm;
        try {
            sm = (Statement) this.connection.createStatement();
            rs = sm.executeQuery(strQuery);
        } catch (SQLException ex) {
            System.out.println("Lỗi:"+ex);
        }
        
       return rs; 
    }
   
    /**
     * Phương thức thêm, xóa, sửa dữ liệu
     * @strQuery strQuery:Chuỗi truy vấn
     * @return :1 nếu thành công, -1 thất bại
     */
    public int executeUpdate(String strQuery) {
       
       Statement sm;
        try {
            sm = (Statement)this.connection.createStatement();
            return sm.executeUpdate(strQuery);
        } catch (SQLException ex) {
            System.out.println("Lỗi:"+ex);
        }
        
       return -1; 
    }
   
   
    /**
     * Phương thức thêm, xóa, sửa dữ liệu sử dụng Transaction
     * @param strQuery:Chuỗi truy vấn
     * @return :1 nếu thành công, -1 thất bại
     */
    public int executeTransaction(String strQuery) {
       Connection con=this.connection;
       Statement sm;
        try {
            con.setAutoCommit(false);
            sm = (Statement)con.createStatement();
            if(sm.executeUpdate(strQuery)==1){
                con.commit();
                return 1;
            }else{
                con.rollback();
                return -1;
            }
        } catch (SQLException ex) {
             System.out.println("Lỗi:"+ex);
        }finally{
            this.close();
        }
            
        
       return -1; 
    }
   
    
    /**
     * Phương thức thêm, xóa, sửa dữ liệu sử dụng Transaction save point
     * @param strQuery:Chuỗi truy vấn
     * @return :1 nếu thành công, -1 thất bại
     */
    public int executeTransactionSavePoint(String strQuery) {
       Connection con=this.connection;
       Statement sm;
        try {
            con.setAutoCommit(false);
            sm = (Statement)con.createStatement();
            //lưu trữ điểm bắt đầu sự thay đổi
            Savepoint savepoint=con.setSavepoint();
            int result=sm.executeUpdate(strQuery);
            if(result>0){
                con.commit();
            }else{
                //phục hồi lại điểm bắt đầu
                con.rollback(savepoint);
            }
            return result;
            
        } catch (SQLException ex) {
             System.out.println("Lỗi:"+ex);
        }finally{
            this.close();
        }
            
        
       return -1; 
    }
    
    /**
     * Thực hiện 1 store procedure bình thương
     * @param storeProcName:Tên store procedure
     * @param para:Tham số của store procedure
     * @return :ResultSet
     */
    public ResultSet executeProcedure(String storeProcName, ArrayList<StoreProcedureParam> para) {
        String value="";
        ResultSet rs=null;
        try {
            
            for (int i = 0; i < para.size(); i++) {
                            
              if(i>0 && i<para.size())
                    value+=",";
              value+="?";
            }
            
            CallableStatement sm=this.connection.prepareCall(String.format("{call %s (%s)}",storeProcName,value));
                           
            for (int i = 0; i < para.size(); i++) {
                StoreProcedureParam sp=para.get(i);
                if(sp.getType().equals("Int")){
                    sm.setInt(sp.getKey(),Integer.parseInt(sp.getValue()));  
                }else if(sp.getType().equals("Float")){
                    sm.setFloat(sp.getKey(),Float.parseFloat(sp.getValue()));                                        
                }else if(sp.getType().equals("String")||sp.getType().equals("DateTime")){
                    sm.setString(sp.getKey(),sp.getValue());                                        
                }else if(sp.getType().equals("Double")){
                    sm.setDouble(sp.getKey(),Double.parseDouble(sp.getValue()));                                        
                }else if(sp.getType().equals("Long")){
                    sm.setLong(sp.getKey(),Long.parseLong(sp.getValue()));                                        
                }else if(sp.getType().equals("DateTime")){
                    sm.setDate(sp.getKey(),Date.valueOf(sp.getValue()));                                        
                }
            }
                       
            sm.execute();
            rs=sm.getResultSet();
            
        } catch (SQLException ex) {
            System.out.println("Lỗi:"+ex);
        }
        return rs;
    }
            
    
    /**
     * Thực hiện 1 store procedure vơi Transaction
     * @param storeProcName:Tên store procedure
     * @param para:Tham số của store procedure
     * @return :1 nếu thành công, -1 nếu thất bại
     */
    public ResultSet executeProcedureTransaction(String storeProcName, ArrayList<StoreProcedureParam> para) {
        String value="";
        ResultSet rs=null;
        Connection con=this.connection;
        try {
            
            for (int i = 0; i < para.size(); i++) {
                            
              if(i>0 && i<para.size())
                    value+=",";
              value+="?";
            }
            
            CallableStatement sm=con.prepareCall(String.format("{call %s (%s)}",storeProcName,value));
                           
           for (int i = 0; i < para.size(); i++) {
                StoreProcedureParam sp=para.get(i);
                if(sp.getType().equals("Int")){
                    sm.setInt(sp.getKey(),Integer.parseInt(sp.getValue()));  
                }else if(sp.getType().equals("Float")){
                    sm.setFloat(sp.getKey(),Float.parseFloat(sp.getValue()));                                        
                }else if(sp.getType().equals("String")||sp.getType().equals("DateTime")){
                    sm.setString(sp.getKey(),sp.getValue());                                        
                }else if(sp.getType().equals("Double")){
                    sm.setDouble(sp.getKey(),Double.parseDouble(sp.getValue()));                                        
                }else if(sp.getType().equals("Long")){
                    sm.setLong(sp.getKey(),Long.parseLong(sp.getValue()));                                        
                }else if(sp.getType().equals("DateTime")){
                    sm.setDate(sp.getKey(),Date.valueOf(sp.getValue()));                                        
                }
            }
            con.setAutoCommit(false);                       
            if(sm.execute()==true){
                con.commit();
                rs=sm.getResultSet();
            }else{
                con.rollback();
            }
            
            
        } catch (SQLException ex) {
            System.out.println("Lỗi:"+ex);
        }
        return rs;
    }
    
    /**
     * Thực hiện 1 store procedure vơi Transaction
     * @param storeProcName:Tên store procedure
     * @param para:Tham số của store procedure
     * @return :ResultSet
     */
    public int procedureTransaction(String storeProcName, ArrayList<StoreProcedureParam> para) {
        String value="";
         Connection con=this.connection;
        try {
            
            for (int i = 0; i < para.size(); i++) {
                            
              if(i>0 && i<para.size())
                    value+=",";
              value+="?";
            }
            
            CallableStatement sm=con.prepareCall(String.format("{call %s (%s)}",storeProcName,value));
                           
            for (int i = 0; i < para.size(); i++) {
                StoreProcedureParam sp=para.get(i);
                if(sp.getType().equals("Int")){
                    sm.setInt(sp.getKey(),Integer.parseInt(sp.getValue()));  
                }else if(sp.getType().equals("Float")){
                    sm.setFloat(sp.getKey(),Float.parseFloat(sp.getValue()));                                        
                }else if(sp.getType().equals("String")||sp.getType().equals("DateTime")){
                    sm.setString(sp.getKey(),sp.getValue());                                        
                }else if(sp.getType().equals("Double")){
                    sm.setDouble(sp.getKey(),Double.parseDouble(sp.getValue()));                                        
                }else if(sp.getType().equals("Long")){
                    sm.setLong(sp.getKey(),Long.parseLong(sp.getValue()));                                        
                }else if(sp.getType().equals("DateTime")){
                    sm.setDate(sp.getKey(),Date.valueOf(sp.getValue()));                                        
                }
            }
            con.setAutoCommit(false);                       
            sm.execute();
            con.commit();
            return 1;
           
            
            
        } catch (SQLException ex) {
            try {                
                con.rollback();
            } catch (SQLException ex1) {
                System.out.println("Không thể RollBack lại dữ liệu ban đầu");
            }
        }
        return -1;
    }
    
    /**
     * Thực hiện 1 store procedure với Transaction save point
     * @param storeProcName:Tên store procedure
     * @param para:Tham số của store procedure
     * @return :ResultSet
     */
    public ResultSet executeProcedureTransactionSavePoint(String storeProcName, ArrayList<StoreProcedureParam> para) {
        String value="";
        ResultSet rs=null;
        Connection con=this.connection;
        try {
            
            for (int i = 0; i < para.size(); i++) {
                            
              if(i>0 && i<para.size())
                    value+=",";
              value+="?";
            }
            
            CallableStatement sm=con.prepareCall(String.format("{call %s (%s)}",storeProcName,value));
                           
            for (int i = 0; i < para.size(); i++) {
                StoreProcedureParam sp=para.get(i);
                if(sp.getType().equals("Int")){
                    sm.setInt(sp.getKey(),Integer.parseInt(sp.getValue()));  
                }else if(sp.getType().equals("Float")){
                    sm.setFloat(sp.getKey(),Float.parseFloat(sp.getValue()));                                        
                }else if(sp.getType().equals("String")||sp.getType().equals("DateTime")){
                    sm.setString(sp.getKey(),sp.getValue());                                        
                }else if(sp.getType().equals("Double")){
                    sm.setDouble(sp.getKey(),Double.parseDouble(sp.getValue()));                                        
                }else if(sp.getType().equals("Long")){
                    sm.setLong(sp.getKey(),Long.parseLong(sp.getValue()));                                        
                }else if(sp.getType().equals("DateTime")){
                    sm.setDate(sp.getKey(),Date.valueOf(sp.getValue()));                                        
                }
            }
            con.setAutoCommit(false);  
            Savepoint savepoint=con.setSavepoint();
            
            if(sm.execute()==true){
                con.commit();
                rs=sm.getResultSet();
            }else{
                con.rollback(savepoint);
            }
            
            
        } catch (SQLException ex) {
            System.out.println("Lỗi:"+ex);
        }
        return rs;
    }
}
